/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools test utils
 */

#include "hmfs_test_utils.h"

#include <algorithm>
#include <array>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <random>
#include <sstream>
#include <sys/wait.h>
#include <unistd.h>

#include "hmfs_encoding.h"
#include "securec.h"

#ifndef O_BINARY
#define O_BINARY 0
#endif

#define CRCPOLY_LE 0xedb88320

#define COMPARE_SB_FIELD(field) (f2SB->field == hmSB->field)
#define COMPARE_CP_FIELD(field) (f2CP->field == hmCP->field)

namespace OHOS {
namespace Hmfs {
template<class Value1, class Value2>
bool CompValue(const Value1 &value1, const Value2 &value2)
{
    return value1 == value2;
}

template<class Value1, class Value2>
bool CompValue(const Value1 first1, const Value1 last1, const Value2 first2)
{
    return std::equal(first1, last1, first2);
}

template<class Value1, class Value2>
bool CompValue(const Value1 first1, const Value1 last1, const Value2 first2, const Value2 last2)
{
    return std::equal(first1, last1, first2, last2);
}

#define COMPARE_FIELD_RET_CODE(superBlockCode, ...) \
    do { \
        if (!CompValue(__VA_ARGS__)) { \
            return superBlockCode; \
        } \
    } while (0)

HmfsCode WriteFile(const std::string &fileName)
{
    if (fileName.empty()) {
        std::cout << "Failed to write file, invalid parameter" << std::endl;
        return HmfsCode::FAILED;
    }

    std::ofstream file(fileName.c_str(), std::ios::binary);
    if (!file.is_open()) {
        std::cout << "Failed to open the file, file name: " << fileName << ", error: " << strerror(errno) << std::endl;
        return HmfsCode::FAILED;
    }

    const std::string text = "Hello, World!";
    if (!file.write(text.c_str(), text.size())) {
        std::cout << "Failed to write file, file name: " << fileName << ", error: " << strerror(errno) << std::endl;
        return HmfsCode::FAILED;
    }
    std::cout << "Succeed in writing file, file name : " << fileName << std::endl;
    return HmfsCode::SUCCESSED;
}

HmfsCode GetFileStat(const std::string &fileName, struct stat *statBuf)
{
    if (fileName.empty() || statBuf == nullptr) {
        std::cout << "Failed to get file status, invalid parameter" << std::endl;
        return HmfsCode::FAILED;
    }

    if (stat(fileName.c_str(), statBuf) != 0) {
        std::cout << "ReadFile Error getting file status : " << strerror(errno) << std::endl;
        return HmfsCode::FAILED;
    }
    std::cout << "Succeed in getting file status, file name : " << fileName << std::endl;
    return HmfsCode::SUCCESSED;
}

std::string ReadFile(const std::string &filePath)
{
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        std::cout << "Failed to open the file, file name: " << filePath << ", error: " << strerror(errno) << std::endl;
        return "";
    }
    std::stringstream buffer;
    buffer << file.rdbuf();
    file.close();
    return buffer.str();
}

unsigned long long GetFileSize(const std::string &fileName)
{
    if (fileName.empty()) {
        std::cout << "Failed to get file size, invalid parameter" << std::endl;
        return (unsigned long long)-1;
    }
    std::ifstream file(fileName, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        std::cout << "Failed to open the file, file name: " << fileName << ", error: " << strerror(errno) << std::endl;
        return (unsigned long long)-1;
    }
    return file.tellg();
}

HmfsCode FAllocateFile(const std::string &fileName)
{
    if (fileName.empty()) {
        std::cout << "Failed to format file, invalid parameter" << std::endl;
        return HmfsCode::FAILED;
    }

    unsigned long long len = GetFileSize(fileName);
    if (len <= 0) {
        std::cout << "Failed to format file, file name : " << fileName << std::endl;
        return HmfsCode::FAILED;
    }

    int fd = open(fileName.c_str(), O_RDWR);
    if (fd == -1) {
        std::cerr << "Failed to open file, file name: " << fileName << ", error: " << strerror(errno) << std::endl;
        return HmfsCode::FAILED;
    }

    unsigned long long offset = 0;
    if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, len) < 0) {
        std::cerr << "Failed to allocate file space, file name: " << fileName << ", file size: " << len <<
            ", error: " << strerror(errno) << std::endl;
        close(fd);
        return HmfsCode::FAILED;
    }
    std::cout << "Succeed in formatting file, file name : " << fileName << std::endl;
    close(fd);
    return HmfsCode::SUCCESSED;
}

HmfsCode CheckDataIsZero(const std::string &fileName)
{
    if (fileName.empty()) {
        std::cout << "Failed to format file, invalid parameter" << std::endl;
        return HmfsCode::ERROR_OTHER;
    }

    std::ifstream file(fileName, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        std::cout << "Failed to open the file, file name : " << fileName << std::endl;
        return HmfsCode::ERROR_OTHER;
    }

    const size_t fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<char> buffer(fileSize);
    if (!file.read(buffer.data(), fileSize)) {
        std::cout << "Failed to read the file, file name : " << fileName << std::endl;
        return HmfsCode::ERROR_OTHER;
    }

    if (std::all_of(buffer.begin(), buffer.end(), [](char c) { return c == '\0'; })) {
        std::cout << "The file " << fileName << " contains only '\\0'." << std::endl;
        return HmfsCode::SUCCESSED;
    } else {
        std::cout << "The file " << fileName << " does not contain only '\\0'." << std::endl;
        return HmfsCode::FAILED;
    }
}

void ClearFile(const std::string &fileName)
{
    if (fileName.empty()) {
        std::cout << "FileName is empty, invalid parameter" << std::endl;
        return;
    }

    int32_t fd = open(fileName.c_str(), O_RDWR);
    if (fd == -1) {
        std::cout << "Failed to open file, errno:" << errno << std::endl;
        return;
    }

    if (ftruncate(fd, 0) == -1) {
        std::cout << "Failed to clear file, errno:" << errno << std::endl;
        close(fd);
    }

    if (ftruncate(fd, TEST_FILE_SIZE) == -1) {
        std::cout << "Failed to clear file, errno:" << errno << std::endl;
        close(fd);
    }

    close(fd);
}

void PrintParameters(const std::vector<std::string> &params)
{
    std::cout << "+----------------------------------------------------------------+" << std::endl;
    std::cout << std::accumulate(params.begin(), params.end(), std::string{},
        [](const std::string &str1, const std::string &str2) {
            return str1.empty() ? str2 : str1 + " " + str2;
        }) << std::endl << std::endl;
    std::cout << "+----------------------------------------------------------------+" << std::endl;
}

// 随机生成一个扇区大小的值
static int32_t GenerateSectorCount(int32_t min, int32_t max)
{
    return min + (std::rand() % (max - min + 1));
}

// 生成随机特性
std::string GenerateFeatures(bool isResizeTool)
{
    std::string features;
    features += (std::rand() % 2 == 0) ? "extra_attr," : "";
    features += (std::rand() % 2 == 0) ? "project_quota," : "";
    features += (std::rand() % 2 == 0) ? "casefold," : "";

    if (!isResizeTool) {
        features += (std::rand() % 2 == 0) ? "inode_checksum," : "";
        features += (std::rand() % 2 == 0) ? "flexible_inline_xattr," : "";
        features += (std::rand() % 2 == 0) ? "inode_crtime," : "";
        features += (std::rand() % 2 == 0) ? "lost_found," : "";
        features += (std::rand() % 2 == 0) ? "verity," : "";
        features += (std::rand() % 2 == 0) ? "quota," : "";
        features += (std::rand() % 2 == 0) ? "sb_checksum," : "";
        features += (std::rand() % 2 == 0) ? "compression," : "";
        features += (std::rand() % 2 == 0) ? "ro," : "";
    }

    return features;
}

std::string GenerateRandomString(const size_t length)
{
    const std::string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    std::mt19937 generator(std::random_device{}());
    std::uniform_int_distribution<> distribution(0, characters.size() - 1);

    std::string randomStr;
    randomStr.reserve(length);
    for (size_t i = 0; i < length; ++i) {
        randomStr += characters[distribution(generator)];
    }

    return randomStr;
}

int32_t GenerateRandomInt32(const int32_t startNum)
{
    std::mt19937 generator(std::random_device{}());
    std::uniform_int_distribution<int32_t> distribution(startNum, INT32_MAX);
    return distribution(generator);
}

void GenerateMkfsParams(std::vector<std::string> &params)
{
    // 随机选择是否加入 -a 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-a");
        params.emplace_back(std::to_string(std::rand() % 2)); // [0, 1]
    }

    // 随机选择是否加入 -e 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-e");
        params.emplace_back(GenerateRandomString(std::rand() % 21 + 1)); // [1, 20]
    }

    // 随机选择是否加入 -E 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-E");
        params.emplace_back(GenerateRandomString(std::rand() % 21 + 1)); // [0, 20]
    }

    // 随机选择是否加入 -m 参数，先不添加m参数，需要特殊设备，配置CONFIG_BLK_DEV_ZONED
    if (std::rand() % 2 == 2) {
        params.emplace_back("-m");
    }

    // 随机选择是否加入 -l 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-l");
        params.emplace_back(GenerateRandomString(std::rand() % 10 + 1)); // [1, 10]
    }

    // 随机选择是否加入 -r 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-r");
    }

    // 随机选择是否加入 -R 参数
    if (std::rand() % 2 == 0) {
        std::string combinedStr = "-R " + std::to_string(GenerateRandomInt32()) + ":" +
            std::to_string(GenerateRandomInt32());
        params.emplace_back(combinedStr);
    }

    // 随机选择是否加入 -s 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-s");
        params.emplace_back(std::to_string(GenerateRandomInt32()));
    }

    // 随机选择是否加入 -t 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-t");
        params.emplace_back(std::to_string(std::rand() % 2)); // [0, 1]
    }

    // 随机选择是否加入 -T 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-T");
        params.emplace_back(std::to_string(GenerateRandomInt32(0)));
    }
}

void GenerateMkfsParamsEnd(std::vector<std::string> &params)
{
    //std::srand(static_cast<uint32_t>(std::time(0)));
    // 随机选择是否加入 -w 参数,期望扇区的大小
    if (std::rand() % 2 == 0) {
        params.emplace_back("-w");
        params.emplace_back(std::to_string(GenerateRandomInt32()));
    }

    // 随机选择是否加入 -z 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-z");
        params.emplace_back(std::to_string(GenerateRandomInt32()));
    }

    const uint8_t deviceCount = std::rand() % MAX_DEVICE_COUNTS;
    // 随机选择是否加入 -c 参数
    if (std::rand() % 2 == 0) {
        for (uint8_t index = 1; index < deviceCount; index++) {
            params.emplace_back("-c");
            params.emplace_back(F2FS_DEVICE_PATH_LIST[index]);
        }
    }
    params.emplace_back(F2FS_DEVICE_PATH_LIST[MAX_DEVICE_COUNTS - 1]);

    // 随机选择是否加入期望扇区的总个数
    if (std::rand() % 2 == 0) {
        params.emplace_back(std::to_string(GenerateRandomInt32()));
    }
}

// 生成参数组合
std::vector<std::string> GenerateParams(bool isResizeTool)
{
    //std::srand(static_cast<uint32_t>(std::time(0)));
    std::vector<std::string> params;
    // 随机选择是否加入 -C 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-C");
        params.emplace_back("utf8");
    }

    // 随机选择是否加入 -O 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-O");
        params.emplace_back(GenerateFeatures(isResizeTool));
    }

    // 随机选择是否加入 -o 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-o");
        params.emplace_back(std::to_string(std::rand() % 101)); // [0, 100]
    }

    // 随机选择是否加入 -d 调试参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-d");
        params.emplace_back(std::to_string(std::rand() % 10)); // [0, 9]
    }

    // 随机选择是否加入 -i 参数
    if (std::rand() % 2 == 0) {
        params.emplace_back("-i");
    }

    if (isResizeTool) {
        // 随机选择是否加入 -s 参数
        if (std::rand() % 3 != 0) {
            params.emplace_back("-s");
        }
        // 添加 -t 扇区个数参数
        params.emplace_back("-t");
        params.emplace_back(std::to_string(GenerateSectorCount(10240, 204800)));
    } else {
        GenerateMkfsParams(params);
        GenerateMkfsParamsEnd(params);
    }

    PrintParameters(params);
    return params;
}

void ReplaceDevicePaths(std::vector<std::string> &params)
{
    for (auto& param : params) {
        for (uint8_t i = 0; i < MAX_DEVICE_COUNTS; ++i) {
            if (param == F2FS_DEVICE_PATH_LIST[i]) {
                param = HMFS_DEVICE_PATH_LIST[i];
            }
        }
    }
}

// 需要确认最后指定的设备是哪个
std::string ConfirmDevicePath(const std::vector<std::string> &params, const bool changePath)
{
    std::vector<std::string>::const_reverse_iterator result = std::find_if(
        params.rbegin(), params.rend(), [changePath](const std::string& str) {
        return str.find(changePath ? F2FS_DEVICE : HMFS_DEVICE) != std::string::npos;
    });

    if (result != params.rend()) {
        std::cout << "Confirm device path : " << *result << std::endl;
        return *result;
    }
    return "";
}

std::string FindSpecifyStr(const std::vector<std::string> &vecStr, const std::string &item)
{
    std::vector<std::string>::const_iterator iter = std::find(vecStr.begin(), vecStr.end(), item);
    if (iter != vecStr.end() && ++iter != vecStr.end()) {
        std::cout << "The value after " << item << " is: " << *iter << std::endl;
        return *iter;
    } else {
        std::cout << "item : " << item << " not found or it's the last element in the vector." << std::endl;
        return "";
    }
}

bool ContainSubStr(const std::string &parameterValue, const std::string &subStr)
{
    size_t pos = parameterValue.find(subStr);
    if (pos != std::string::npos) {
        std::cout << "Found '" << subStr << "' in value at position: " << pos << std::endl;
        std::string ro("ro");
        if (subStr == ro && ((pos + ro.length() >= parameterValue.length()) ||
            parameterValue[pos + ro.length()] != ',')) {
            return false;
        }
        return true;
    } else {
        std::cout << "'" << subStr << "' not found in value." << std::endl;
        return false;
    }
}

bool CheckFeatures(const uint32_t features, const std::string &featureNameList)
{
    std::unordered_map<std::string, uint32_t> featureMap = {
        { "encrypt",                HMFS_FEATURE_ENCRYPT },
        { "extra_attr",             HMFS_FEATURE_EXTRA_ATTR },
        { "project_quota",          HMFS_FEATURE_PRJQUOTA },
        { "inode_checksum",         HMFS_FEATURE_INODE_CHKSUM },
        { "flexible_inline_xattr",  HMFS_FEATURE_FLEXIBLE_INLINE_XATTR },
        { "quota",                  HMFS_FEATURE_QUOTA_INO },
        { "inode_crtime",           HMFS_FEATURE_INODE_CRTIME },
        { "lost_found",             HMFS_FEATURE_LOST_FOUND },
        { "verity",                 HMFS_FEATURE_VERITY },
        { "sb_checksum",            HMFS_FEATURE_SB_CHKSUM },
        { "casefold",               HMFS_FEATURE_CASEFOLD },
        { "compression",            HMFS_FEATURE_COMPRESSION },
        { "ro",                     HMFS_FEATURE_RO},
    };

    for (const auto &[key, feature] : featureMap) {
        if (ContainSubStr(featureNameList, key) && (!(features & feature))) {
            return false;
        }
    }
    return true;
}

bool CheckParametersVaild(const std::vector<std::string> &params, std::map<std::string, std::string> &parameterMap)
{
    std::string value;
    for (const std::string &param : HMFS_PARAMETER_LIST) {
        std::cout << "Parameter: " << param << std::endl;
        value = FindSpecifyStr(params, param);
        if (value.empty()) {
            continue;
        }
        if ((param == "-s" || param == "-w" || param == "-z") && (static_cast<int32_t>(std::stoi(value) <= 0))) {
            return false;
        }
        if ((param == "-O") && ((ContainSubStr(value, "project_quota") || ContainSubStr(value, "inode_checksum") ||
            ContainSubStr(value, "flexible_inline_xattr") || ContainSubStr(value, "inode_crtime") ||
            ContainSubStr(value, "compression")) && (!ContainSubStr(value, "extra_attr")))) {
            return false;
        }
        parameterMap[param] = value;
        value.clear();
    }
    return true;
}

int32_t CheckResizeParameters(std::string &device, const std::vector<std::string> &params,
    const uint32_t deviceSectorCount, std::map<std::string, std::string> &parameterMap)
{
    auto hmfsSuperBlock = std::make_unique<SuperBlockData>();
    GetSuperBlock(device, hmfsSuperBlock);
    if (std::find(params.begin(), params.end(), "-i") != params.end()) {
        parameterMap["-i"] = "";
    }
    bool hasSafeResizeFlag = (std::find(params.begin(), params.end(), "-s") != params.end());
    for (const std::string &param : HMFS_RESIZE_PARAMETER_LIST) {
        std::string value = FindSpecifyStr(params, param);
        if (value.empty()) {
            continue;
        }
        if (param == "-t") {
            uint64_t num = std::stoull(value);
            if ((num >> hmfsSuperBlock->log2SectorsPerBlock) < hmfsSuperBlock->blockCount && !hasSafeResizeFlag) {
                return NEED_SAFE_RESIZE_FLAG;
            }
            if (num > deviceSectorCount) {
                return OUT_OF_RANGE;
            }
        }
        parameterMap[param] = value;
    }
    if (!CheckSafeResize(parameterMap, hmfsSuperBlock)) {
        std::cout << "MORE_SEGMENT_NEEDED" << std::endl;
        return MORE_SEGMENT_NEEDED;
    }
    return VALID;
}

bool CheckSafeResize(const std::map<std::string, std::string> &parameterMap, const std::unique_ptr<SuperBlockData> &superBlock)
{
    SuperBlockData newSuperBlock = *superBlock;
    uint32_t segmentSizeBytes = 1 << (newSuperBlock.logBlockSize + newSuperBlock.logBlksPerSeg);
    uint32_t segsPerZone = newSuperBlock.segsPerSection * newSuperBlock.sectionsPerZone;
    uint64_t targetSectors = 0;
    auto it = parameterMap.find("-t");
    if (it != parameterMap.end()) {
        std::string parameterValue = it->second;
        if (!parameterValue.empty()) {
            targetSectors = std::stoull(parameterValue);
        }
    }
    newSuperBlock.blockCount = targetSectors >> newSuperBlock.log2SectorsPerBlock;
    uint32_t zoneSizeBytes = segmentSizeBytes * segsPerZone;
    uint32_t startSector = 0;
    uint64_t zoneAlignStartOffset = ((uint64_t) startSector * DEFAULT_SECTOR_SIZE + 2 * HMFS_BLOCK_SIZE + zoneSizeBytes - 1) /
        zoneSizeBytes * zoneSizeBytes - (uint64_t) startSector * DEFAULT_SECTOR_SIZE;
    newSuperBlock.segmentCount = (targetSectors * DEFAULT_SECTOR_SIZE - zoneAlignStartOffset) /
        segmentSizeBytes / newSuperBlock.segsPerSection * newSuperBlock.segsPerSection;
    newSuperBlock.segmentCountInMain = newSuperBlock.segmentCount - newSuperBlock.segmentCountInCP -
        newSuperBlock.segmentCountInSIT - newSuperBlock.segmentCountInNAT - newSuperBlock.segmentCountInSSA;
    newSuperBlock.sectionCount = newSuperBlock.segmentCountInMain / newSuperBlock.segsPerSection;
    newSuperBlock.segmentCountInMain = newSuperBlock.sectionCount * newSuperBlock.segsPerSection;
    double overprovision = 0;
    it = parameterMap.find("-o");
    if (it != parameterMap.end()) {
        std::string parameterValue = it->second;
        if (!parameterValue.empty()) {
            overprovision = std::stod(parameterValue);
        }
    }
    if (overprovision == 0) {
        overprovision = HmfsCommon::GetInstance().GetBestOverProvision(&newSuperBlock);
    }
    uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * newSuperBlock.segsPerSection;
    uint32_t blksPerSeg = 1 << newSuperBlock.logBlksPerSeg;
    if ((newSuperBlock.segmentCountInMain - 2) < reservedSegments ||
        newSuperBlock.segmentCountInMain * blksPerSeg > newSuperBlock.blockCount) {
        // std::cout << "\tError: Device size is not sufficient for F2FS volume, "
        //     "more segment needed" << reservedSegments - (superBlock.segmentCountInMain - 2) << std::endl;
        return false;
    }
    return true;
}

bool CheckResizeHmfsResult(const std::map<std::string, std::string> &parameterMap,
    const std::unique_ptr<CheckPointData> &checkPoint,
    const std::unique_ptr<SuperBlockData> &superBlock,
    const std::string &output)
{
    if (checkPoint == nullptr || superBlock == nullptr) {
        return false;
    }

    // 校验-t参数
    auto CheckParameterT = [&](const std::string& parameterValue) -> bool {
        if (parameterValue.empty()) {
            return true;
        }
        uint64_t targetSectors = std::stoull(parameterValue);
        if (superBlock->blockCount != (targetSectors >> superBlock->log2SectorsPerBlock)) {
            std::cout << "Failed to check the result of parameter 't'" << std::endl;
            return false;
        }
        return true;
    };

    // 校验-o参数
    auto CheckParameterO = [&](const std::string& parameterValue) -> bool {
        if (parameterValue.empty()) {
            return true;
        }
        double overprovision = std::stod(parameterValue);
        if (overprovision == 0) {
            overprovision = HmfsCommon::GetInstance().GetBestOverProvision(superBlock.get());
        }

        uint32_t reservedSegments = (2 * (100 / overprovision + 1) + 6) * superBlock->segsPerSection;
        std::cout << "test parameter o, reservedSegments = " << reservedSegments << std::endl;

        uint32_t overprov_segment_count = (superBlock->segmentCountInMain - reservedSegments) * overprovision / 100;
        overprov_segment_count += reservedSegments;
        std::cout << "test parameter o, overprov_segment_count = " << overprov_segment_count << std::endl;

        if (checkPoint->overprovisionSegmentCount != overprov_segment_count ||
            checkPoint->reservedSegmentCount != reservedSegments) {
            std::cout << "Failed to check the result of parameter 'o'" << std::endl;
            return false;
        }
        return true;
    };

    // 校验-i参数
    auto CheckParameterI = [&](const std::string& parameterValue) -> bool {
        if (!parameterValue.empty() && !(checkPoint->checkPointFlags & CP_FLAG_LARGE_NAT_BITMAP)) {
            std::cout << "Failed to check the result of parameter 'i'" << std::endl;
            return false;
        }
        return true;
    };

    // 校验-C参数
    auto CheckParameterC = [&](const std::string& parameterValue) -> bool {
        if (!parameterValue.empty() &&
            (!(superBlock->encoding == HMFS_ENC_UTF8_12_1)) &&
            (!(superBlock->features & HMFS_FEATURE_CASEFOLD))) {
            std::cout << "Failed to check the result of parameter 'C'" << std::endl;
            return false;
        }
        return true;
    };

    // 校验-O参数
    auto CheckParameterOFeatures = [&](const std::string &parameterValue) -> bool {
        if (parameterValue.empty()) {
            return true;
        }

        std::unordered_map<std::string, uint32_t> featureMap = {
            { "extra_attr", HMFS_FEATURE_EXTRA_ATTR },
            { "project_quota", HMFS_FEATURE_PRJQUOTA },
            { "casefold", HMFS_FEATURE_CASEFOLD },
        };

        for (const auto &[key, feature] : featureMap) {
            if (ContainSubStr(parameterValue, key) && !(superBlock->features & feature)) {
                std::cout << "Failed to check the result of parameter 'O'" << std::endl;
                return false;
            }
        }
        return true;
    };

    // 参数检查逻辑
    const std::vector<std::pair<std::string, std::function<bool(const std::string&)>>> parameterCheckers = {
        { "-t", CheckParameterT },
        { "-o", CheckParameterO },
        { "-i", CheckParameterI },
        { "-C", CheckParameterC },
        { "-O", CheckParameterOFeatures },
    };

    for (const auto &[param, checker] : parameterCheckers) {
        auto it = parameterMap.find(param);
        if (it != parameterMap.end() && !checker(it->second)) {
            return false;
        }
    }
    return true;
}

static int VerifyCheckSum(CheckPointData *checkPoint)
{
    if (checkPoint == nullptr) {
        std::cout << "VerifyCheckSum invalid parameter" << std::endl;
        return -1;
    }
    uint32_t checksumOffset = GetLeValue(checkPoint->checksumOffset);
    uint32_t crc, calCrc;

    if (checksumOffset < CP_MIN_CHECKSUM_OFFSET || checksumOffset > CP_CHECKSUM_OFFSET) {
        std::cout << "Invalid checkPoint crc offset" << std::endl;
        return -1;
    }

    crc = LE32ToNative(*(reinterpret_cast<uint32_t*>((reinterpret_cast<unsigned char *>(checkPoint) + checksumOffset))));
    calCrc = HmfsCommon::GetInstance().GetCheckpointChksum(checkPoint);
    if (calCrc != crc) {
        std::cout << "Invalid CP CRC: offset: "<< checksumOffset << "crc: " << crc << "calCrc: "<< calCrc << std::endl;
        return -1;
    }

    return 0;
}

static bool ValidateCheckpoint(const std::string &devPath, uint32_t cpBlkAddr, CheckPointData *checkPoint)
{
    if (devPath.empty() || cpBlkAddr <= 0) {
        std::cout << "ValidateCheckpoint invalid parameter" << std::endl;
        return false;
    }

    int fd = open(devPath.c_str(), O_RDWR | O_BINARY);
    if (fd < 0) {
        std::cout << "Failed to open " << devPath << " errno " << errno << std::endl;
        return false;
    }

    std::array<char, PREAD_BUFFER_SIZE> buf{};
    ssize_t readSize = pread64(fd, buf.data(), PREAD_BUFFER_SIZE, cpBlkAddr << 12);
    if (readSize < 0) {
        std::cout << "Failed to pread64, errno " << errno << std::endl;
        close(fd);
        return false;
    }

    CheckPointData *checkPoint1 = reinterpret_cast<CheckPointData*>(buf.data());
    if (VerifyCheckSum(checkPoint1)) {
        std::cout << " page1 VerifyCheckSum is failed" << std::endl;
        close(fd);
        return false;
    }

    cpBlkAddr += GetLeValue(checkPoint1->checkPointPackBlockCount) - 1;

    std::array<char, PREAD_BUFFER_SIZE> buf1{};
    readSize = pread64(fd, buf1.data(), PREAD_BUFFER_SIZE, cpBlkAddr << 12);
    if (readSize < 0) {
        std::cout << "Failed to pread64, errno " << errno << std::endl;
        close(fd);
        return false;
    }
    close(fd);

    CheckPointData *checkPoint2 = reinterpret_cast<CheckPointData*>(buf1.data());
    if (VerifyCheckSum(checkPoint2)) {
        std::cout << " page2 VerifyCheckSum is failed" << std::endl;
        return false;
    }

    if (GetLeValue(checkPoint1->checkPointVersion) == GetLeValue(checkPoint2->checkPointVersion)) {
        if (memcpy_s(checkPoint, PREAD_BUFFER_SIZE, checkPoint1, PREAD_BUFFER_SIZE) != 0) {
            std::cout << "Failed to copy checkPoint" << std::endl;
        }
        return true;
    }

    return false;
}

void GetCheckPoint(const std::string &devPath, std::unique_ptr<CheckPointData> &checkPoint)
{
    if (devPath.empty() || checkPoint == nullptr) {
        std::cout << "GetCheckPoint invalid parameter" << std::endl;
        return;
    }

    auto superBlock = std::make_unique<SuperBlockData>();
    GetSuperBlock(devPath, superBlock);
    uint32_t checkPointBlockId = GetLeValue(superBlock->checkPointBlockId);
    uint32_t blocksize = 1 << GetLeValue(superBlock->logBlockSize);

    auto ckpt1 = std::make_unique<uint8_t[]>(blocksize);
    int ret1 = ValidateCheckpoint(devPath, checkPointBlockId, reinterpret_cast<CheckPointData*>(ckpt1.get()));
    uint64_t cpVersion1 = reinterpret_cast<CheckPointData*>(ckpt1.get())->checkPointVersion;

    auto ckpt2 = std::make_unique<uint8_t[]>(blocksize);
    checkPointBlockId += 1 << GetLeValue(superBlock->logBlksPerSeg);
    int ret2 = ValidateCheckpoint(devPath, checkPointBlockId, reinterpret_cast<CheckPointData*>(ckpt2.get()));

    uint64_t cpVersion2 = reinterpret_cast<CheckPointData*>(ckpt2.get())->checkPointVersion;

    if (ret1 && ret2) {
        std::cout << "cpVersion1 " << cpVersion1 << " cpVersion2 " << cpVersion2 << std::endl;
        if (cpVersion2 > cpVersion1) {
            checkPoint.reset(reinterpret_cast<CheckPointData*>(ckpt2.release()));
        } else {
            checkPoint.reset(reinterpret_cast<CheckPointData*>(ckpt1.release()));
        }
    } else if (ret1) {
        checkPoint.reset(reinterpret_cast<CheckPointData*>(ckpt1.release()));
    } else if (ret2) {
        checkPoint.reset(reinterpret_cast<CheckPointData*>(ckpt2.release()));
    } else {
        std::cout << "GetCheckPoint failed!" << std::endl;
    }
}

void GetSuperBlock(const std::string &devPath, std::unique_ptr<SuperBlockData> &superBlock)
{
    std::cout << "GetSuperBlock begin" << std::endl;

    if (devPath.empty() || superBlock == nullptr) {
        std::cout << "GetSuperBlock invalid parameter" << std::endl;
        return;
    }

    std::array<char, PREAD_BUFFER_SIZE> buf {};
    int fd = open(devPath.c_str(), O_RDWR | O_BINARY);
    if (fd < 0) {
        std::cout << "Failed to open " << devPath << " errno " << errno << std::endl;
        return;
    }

    if (pread64(fd, buf.data(), buf.size(), 0) < 0) {
        std::cout << "Failed to pread64, errno " << errno << std::endl;
        close(fd);
        return;
    }
    close(fd);

    if (memcpy_s(superBlock.get(), sizeof(*superBlock), buf.data() + SUPER_BLOCK_OFFSET, sizeof(*superBlock)) != 0) {
        std::cout << "Failed to copy superBlockData" << std::endl;
        return;
    }

    std::cout << "GetSuperBlock end" << std::endl;
}

int32_t ExecutableCmd(const char *path, char *const argv[])
{
    if (path == nullptr || argv == nullptr ) {
        return -1;
    }

    pid_t pid = fork();
    if (pid < 0) {
        return -errno;
    }

    if (pid == 0) {
        if (execv(path, argv) == -1) {
            _exit(EXIT_FAILURE);
        }
    }

    int status = -1;
    pid_t wpid = waitpid(pid, &status, 0);
    if (wpid == -1) {
        return -errno;
    }

    if (WIFEXITED(status)) {
        return WEXITSTATUS(status);
    }
    return -ECHILD;
}

int32_t ExecutableCmd(const char *path, char *const argv[], uint64_t &runTime)
{
    if (path == nullptr || argv == nullptr) {
        return -1;
    }

    int pipeFd[2]; // 2 is read write
    if (pipe(pipeFd) == -1) {
        return -errno;
    }

    pid_t pid = fork();
    if (pid < 0) {
        close(pipeFd[0]);
        close(pipeFd[1]);
        return -errno;
    }

    if (pid == 0) {
        close(pipeFd[0]);
        uint64_t startTime = GetCurrentTime();
        write(pipeFd[1], &startTime, sizeof(startTime));
        close(pipeFd[1]);
        if (execv(path, argv) == -1) {
            _exit(EXIT_FAILURE);
        }
    }

    close(pipeFd[1]);
    uint64_t startTime;
    read(pipeFd[0], &startTime, sizeof(startTime));
    close(pipeFd[0]);
    int status = -1;
    uint64_t endTime = 0;
    pid_t wpid = waitpid(pid, &status, 0);
    if (wpid == -1) {
        endTime = GetCurrentTime();
        runTime = endTime - startTime;
        return -errno;
    }

    if (WIFEXITED(status)) {
        endTime = GetCurrentTime();
        runTime = endTime - startTime;
        return WEXITSTATUS(status);
    }
    endTime = GetCurrentTime();
    runTime = endTime - startTime;
    return -ECHILD;
}

int32_t ExecMkfsBinary(const std::string &fsType, const std::string &devPath, const std::vector<std::string> &params)
{
    uint64_t runTime = 0;
    return ExecMkfsBinary(fsType, devPath, params, runTime);
}

int32_t ExecMkfsBinary(const std::string &fsType, const std::string &devPath, const std::vector<std::string> &params,
    uint64_t &runTime)
{
    std::vector<char*> argv;
    if (fsType == F2FS_TYPE) {
        argv.emplace_back(const_cast<char*>(F2FS_MKFS_BINARY_PATH.c_str()));
    }
    if (fsType == HMFS_TYPE) {
        argv.emplace_back(const_cast<char*>(HMFS_MKFS_BINARY_PATH.c_str()));
    }
    for (const auto &param : params) {
        argv.emplace_back(const_cast<char*>(param.c_str()));
    }
#ifndef MKFS_MULTI_TEST
    argv.emplace_back(const_cast<char*>(devPath.c_str()));
#endif
    argv.emplace_back(nullptr);
    return ExecutableCmd(argv[0], argv.data(), runTime);
}

void ExecutableDdCmd(const std::string &device, int32_t count)
{
    std::string deviceStr = "of=" + device;
    std::string countStr = "count=" + std::to_string(count);
    std::vector<char*> argv;
    argv.push_back(const_cast<char*>("/system/bin/dd"));
    argv.push_back(const_cast<char*>("if=/dev/zero"));
    argv.push_back(const_cast<char*>(deviceStr.c_str()));
    argv.push_back(const_cast<char*>("bs=1M"));
    argv.push_back(const_cast<char*>(countStr.c_str()));
    argv.push_back(nullptr);
    (void)ExecutableCmd(argv[0], argv.data());
    system("sleep 2");
}

uint64_t GetCurrentTime()
{
    struct timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);
    return static_cast<uint64_t>(now.tv_sec) * SEC_TO_MSEC + static_cast<uint64_t>(now.tv_nsec) / MSEC_TO_NSEC;
}

bool CompareRunTime(uint64_t f2fsTime, uint64_t hmfsTime)
{
    const uint64_t maxDiff = 40;
    const double maxPercentageDiff = 10.0;
    std::cout << "f2fsTime : " << f2fsTime << " hmfsTime : " << hmfsTime << std::endl; // only show run time
    if (f2fsTime == 0 || hmfsTime == 0) {
        std::cout << "f2fsTime : " << f2fsTime << " hmfsTime : " << hmfsTime << std::endl;
        return false;
    }
    if (f2fsTime >= hmfsTime) {
        return true;
    }
    uint64_t diff = hmfsTime - f2fsTime;
    if (diff <= maxDiff) {
        return true;
    }
    double percentageDiff = (static_cast<double>(diff) / f2fsTime) * 100.0;
    if (percentageDiff <= maxPercentageDiff) {
        return true;
    }
    std::cout << "f2fsTime : " << f2fsTime << " hmfsTime : " << hmfsTime << " percentageDiff : " <<
        percentageDiff << std::endl;
    return false;
}

void DataDuplicatorDevice(const std::string &devicePath)
{
    std::vector<char*> argv;
    argv.emplace_back(const_cast<char*>("/system/bin/dd"));
    argv.emplace_back(const_cast<char*>("if=/dev/zero"));

    std::string outputFile = "of=" + devicePath;
    argv.emplace_back(const_cast<char*>(outputFile.c_str()));
    argv.emplace_back(const_cast<char*>("bs=1M"));
    argv.emplace_back(const_cast<char*>("count=100"));
    argv.emplace_back(nullptr);
    ExecutableCmd(argv[0], argv.data());
}

int32_t ExecutableCmdWithOutput(std::vector<std::string> &params, std::string &outputFile)
{
    pid_t pid = fork();
    if (pid < 0) {
        std::cout << "Failed to fork! errno: " << errno << std::endl;
        return -errno;
    }
    if (pid == 0) {
        int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
        if (fd < 0) {
            std::cout << "Failed to open output file, errno " << errno << std::endl;
            _exit(EXIT_FAILURE);
        }
        fflush(stdout);
        dup2(fd, fileno(stdout));
        close(fd);
        std::vector<char*> argv;
        for (const auto& param : params) {
            argv.push_back(const_cast<char*>(param.c_str()));
        }
        argv.push_back(nullptr);
        std::cout << "Begin exec dump" << std::endl;
        execv(argv[0], argv.data());
        _exit(EXIT_FAILURE);
    }

    int status = -1;
    pid_t wpid = waitpid(pid, &status, 0);
    if (wpid == -1 || wpid != pid) {
        std::cout << "Failed to exec cmd! wpid: " << wpid << " pid: " << pid << std::endl;
        return -errno;
    }

    if (WIFEXITED(status)) {
        std::cout << "Child process exit status: " << WEXITSTATUS(status) << std::endl;
        return WEXITSTATUS(status);
    }
    std::cout << "Failed to exec cmd!" << std::endl;
    return -ECHILD;
}

int32_t ExecutableCmdWithOutput(std::vector<std::string> &params, std::string &outputFile, uint64_t &runTime)
{
    int pipeFd[2];
    if (pipe(pipeFd) == -1) {
        return -errno;
    }

    pid_t pid = fork();
    if (pid < 0) {
        close(pipeFd[0]);
        close(pipeFd[1]);
        std::cout << "Failed to fork! errno: " << errno << std::endl;
        return -errno;
    }
    if (pid == 0) {
        close(pipeFd[0]);
        uint64_t startTime = GetCurrentTime();
        write(pipeFd[1], &startTime, sizeof(startTime));
        close(pipeFd[1]);
        int fd = open(outputFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
        if (fd < 0) {
            std::cout << "Failed to open output file, errno " << errno << std::endl;
            _exit(EXIT_FAILURE);
        }
        fflush(stdout);
        dup2(fd, fileno(stdout));
        close(fd);
        std::vector<char*> argv;
        for (const auto& param : params) {
            argv.push_back(const_cast<char*>(param.c_str()));
        }
        argv.push_back(nullptr);
        std::cout << "Begin exec dump" << std::endl;
        execv(argv[0], argv.data());
        _exit(EXIT_FAILURE);
    }

    close(pipeFd[1]);
    uint64_t startTime;
    read(pipeFd[0], &startTime, sizeof(startTime));
    close(pipeFd[0]);
    int status = -1;
    uint64_t endTime = 0;
    pid_t wpid = waitpid(pid, &status, 0);
    if (wpid == -1 || wpid != pid) {
        endTime = GetCurrentTime();
        runTime = endTime - startTime;
        std::cout << "Failed to exec cmd! wpid: " << wpid << " pid: " << pid << std::endl;
        return -errno;
    }

    if (WIFEXITED(status)) {
        endTime = GetCurrentTime();
        runTime = endTime - startTime;
        std::cout << "Child process exit status: " << WEXITSTATUS(status) << std::endl;
        return WEXITSTATUS(status);
    }
    endTime = GetCurrentTime();
    runTime = endTime - startTime;
    std::cout << "Failed to exec cmd!" << std::endl;
    return -ECHILD;
}

int32_t ExecFsckWithOutput(std::string &device, std::string &outputFile)
{
    std::vector<std::string> argv;
    argv.push_back("/system/bin/fsck.f2fs");
    argv.push_back("--dry-run");
    argv.push_back(device);
    return ExecutableCmdWithOutput(argv, outputFile);
}

bool ExecFsckBinaryAndCheck(const std::string &devPath)
{
    std::string outputFile = "/data/local/fsck.txt";
    std::vector<std::string> argv;
    argv.push_back("/system/bin/fsck.f2fs");
    argv.push_back("--dry-run");
    argv.push_back(devPath);

    if (ExecutableCmdWithOutput(argv, outputFile) != 0) {
        std::cout << "Exec fsck failed" << std::endl;
        system("rm -rf /data/local/fsck.txt");
        return false;
    }
    bool ret = PrintFsckErrorMsg(outputFile,devPath);
    system("rm -rf /data/local/fsck.txt");
    return ret;
}

int32_t ExecResizeBinary(std::string tool, std::vector<std::string> &params, std::string device)
{
    uint64_t runTime = 0;
    return ExecResizeBinary(tool, params, device, runTime);
}

int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector<std::string> &params,
    std::string device, std::string &outputFile)
{
    uint64_t runTime = 0;
    return ExecResizeBinaryWithOutput(tool, params, device, outputFile, runTime);
}

int32_t ExecResizeBinary(std::string tool, std::vector<std::string> &params, std::string device, uint64_t &runTime)
{
    std::vector<char*> argv;
    if (tool == F2FS_TYPE) {
        argv.emplace_back(const_cast<char*>(F2FS_RESIZE_BINARY_PATH.c_str()));
    }
    if (tool == HMFS_TYPE) {
        argv.emplace_back(const_cast<char*>(HMFS_RESIZE_BINARY_PATH.c_str()));
    }
    for (const auto &param : params) {
        argv.push_back(const_cast<char*>(param.c_str()));
    }
    argv.push_back(const_cast<char*>(device.c_str()));
    argv.push_back(nullptr);
    return ExecutableCmd(argv[0], argv.data(), runTime);
}

int32_t ExecResizeBinaryWithOutput(std::string tool, std::vector<std::string> &params,
    std::string device, std::string &outputFile, uint64_t &runTime)
{
    std::vector<std::string> argv;
    if (tool == F2FS_TYPE) {
        argv.emplace_back(const_cast<char*>(F2FS_RESIZE_BINARY_PATH.c_str()));
    }
    if (tool == HMFS_TYPE) {
        argv.emplace_back(const_cast<char*>(HMFS_RESIZE_BINARY_PATH.c_str()));
    }
    for (const auto& param : params) {
        argv.push_back(param);
    }
    argv.push_back(device);
    return ExecutableCmdWithOutput(argv, outputFile, runTime);
}

int32_t RemoveFile(std::string &file)
{
    std::vector<char*> argv;
    std::string cmdStr = "rm -rf " + file;
    argv.push_back(const_cast<char*>("/bin/sh"));
    argv.push_back(const_cast<char*>("-c"));
    argv.push_back(const_cast<char*>(cmdStr.c_str()));
    argv.push_back(nullptr);

    return ExecutableCmd(argv[0], argv.data());
}

static int16_t ParseInodeAddrIndex(const std::string &addr)
{
    int16_t addrIndex = -1;
    std::string toFind = "[0x";
    std::size_t pos = addr.find(toFind);
    if (pos != std::string::npos) {
        pos += toFind.length();
        std::string hexStr;
        std::size_t endPos = addr.find(']', pos);
        if (endPos != std::string::npos) {
            hexStr = addr.substr(pos, endPos - pos);
            addrIndex = std::stoi(hexStr, nullptr, 16);
        }
    }
    if (addrIndex >= ADDR_COUNT_PER_INODE) {
        addrIndex = -1;
    }
    return addrIndex;
}

void GetNodeDataFromMap(std::unique_ptr<NodeData> &nodeData, int16_t &addrIndex,
    const std::unordered_map<std::string, uint64_t> &inodeInfo)
{
    static const std::unordered_map<std::string, std::function<void(NodeData *, uint64_t)>> inodeMap = {
        {"i_mode", [](NodeData *nd, uint64_t v) { nd->inode.fileMode = static_cast<uint16_t>(v); }},
        {"i_advise", [](NodeData *nd, uint64_t v) { nd->inode.fileHints = static_cast<uint8_t>(v); }},
        {"i_uid", [](NodeData *nd, uint64_t v) { nd->inode.userId = static_cast<uint32_t>(v); }},
        {"i_gid", [](NodeData *nd, uint64_t v) { nd->inode.groupId = static_cast<uint32_t>(v); }},
        {"i_links", [](NodeData *nd, uint64_t v) { nd->inode.linkCount = static_cast<uint32_t>(v); }},
        {"i_size", [](NodeData *nd, uint64_t v) { nd->inode.fileSize = v; }},
        {"i_blocks", [](NodeData *nd, uint64_t v) { nd->inode.blockSize = v; }},
        {"i_atime", [](NodeData *nd, uint64_t v) { nd->inode.accessTime = v; }},
        {"i_atime_nsec", [](NodeData *nd, uint64_t v) { nd->inode.accessTimeNsec = static_cast<uint32_t>(v); }},
        {"i_ctime", [](NodeData *nd, uint64_t v) { nd->inode.changeTime = v; }},
        {"i_ctime_nsec", [](NodeData *nd, uint64_t v) { nd->inode.changeTimeNsec = static_cast<uint32_t>(v); }},
        {"i_mtime", [](NodeData *nd, uint64_t v) { nd->inode.modificationTime = v; }},
        {"i_mtime_nsec", [](NodeData *nd, uint64_t v) { nd->inode.modificationTimeNsec = static_cast<uint32_t>(v); }},
        {"i_generation", [](NodeData *nd, uint64_t v) { nd->inode.fileVersion = static_cast<uint32_t>(v); }},
        {"i_current_depth", [](NodeData *nd, uint64_t v) { nd->inode.directoryDepth = static_cast<uint32_t>(v); }},
        {"i_xattr_nid", [](NodeData *nd, uint64_t v) { nd->inode.xattrNodeId = static_cast<uint32_t>(v); }},
        {"i_flags", [](NodeData *nd, uint64_t v) { nd->inode.fileAttributes = static_cast<uint32_t>(v); }},
        {"i_inline", [](NodeData *nd, uint64_t v) { nd->inode.inlineFlags = static_cast<uint8_t>(v); }},
        {"i_pino", [](NodeData *nd, uint64_t v) { nd->inode.parentInodeNumber = static_cast<uint32_t>(v); }},
        {"i_dir_level", [](NodeData *nd, uint64_t v) { nd->inode.directoryLevel = static_cast<uint8_t>(v); }},
        {"i_crtime", [](NodeData *nd, uint64_t v) { nd->inode.creationTime = v; }},
        {"i_crtime_nsec", [](NodeData *nd, uint64_t v) { nd->inode.creationTimeNsec = static_cast<uint32_t>(v); }},
        {"i_inode_checksum", [](NodeData *nd, uint64_t v) { nd->inode.inodeChecksum = static_cast<uint32_t>(v); }},
        {"i_extra_isize", [](NodeData *nd, uint64_t v) { nd->inode.extraInodeSize = static_cast<uint16_t>(v); }},
        {"i_inline_xattr_size", [](NodeData *nd, uint64_t v) { nd->inode.inlineXattrSize = static_cast<uint16_t>(v); }},
        {"i_projid", [](NodeData *nd, uint64_t v) { nd->inode.projectId = static_cast<uint32_t>(v); }},
        {"i_compr_blocks", [](NodeData *nd, uint64_t v) { nd->inode.compressedBlockCount = v; }},
        {"i_compress_algrithm", [](NodeData *nd, uint64_t v) { nd->inode.compressionAlgorithm = static_cast<uint8_t>(v); }},
        {"i_log_cluster_size", [](NodeData *nd, uint64_t v) { nd->inode.logClusterSize = static_cast<uint8_t>(v); }},
        {"i_padding", [](NodeData *nd, uint64_t v) { nd->inode.padding = static_cast<uint16_t>(v); }},
        {"nodeIds[0]", [](NodeData* nd, uint64_t v) { nd->inode.nodeIds[0] = static_cast<uint32_t>(v); }},
        {"nodeIds[1]", [](NodeData* nd, uint64_t v) { nd->inode.nodeIds[1] = static_cast<uint32_t>(v); }},
        {"nodeIds[2]", [](NodeData* nd, uint64_t v) { nd->inode.nodeIds[2] = static_cast<uint32_t>(v); }},
        {"nodeIds[3]", [](NodeData* nd, uint64_t v) { nd->inode.nodeIds[3] = static_cast<uint32_t>(v); }},
        {"nodeIds[4]", [](NodeData* nd, uint64_t v) { nd->inode.nodeIds[4] = static_cast<uint32_t>(v); }},
    };

    for (const auto &element : inodeInfo) {
        auto pos = element.first.find("dataBlocksAddr");
        if (pos != std::string::npos) {
            addrIndex = ParseInodeAddrIndex(element.first);
            if (addrIndex != -1) {
                nodeData->inode.dataBlocksAddr[addrIndex] = element.second;
                std::cout << "i.dataBlocksAddr[0x" << std::hex << addrIndex << "] = " <<
                    std::dec << element.second << std::endl;
                continue;
            }
        }

        auto it = inodeMap.find(element.first);
        if (it != inodeMap.end()) {
            it->second(nodeData.get(), element.second);
        } else {
            std::cout << "Unknown key: " << element.first << std::endl;
        }
    }
}

std::unordered_map<std::string, uint64_t> ParseInodeInfo(const std::string &outputFile)
{
    std::unordered_map<std::string, uint64_t> inodeInfo;
    std::ifstream file(outputFile);
    if (!file.is_open()) {
        return inodeInfo;
    }

    std::string line;
    while (std::getline(file, line)) {
        size_t leftBracket = line.rfind("[0x");
        size_t colon = line.find(':');
        size_t rightBracket = line.rfind(']');

        if (leftBracket != std::string::npos && colon != std::string::npos && rightBracket != std::string::npos) {
            std::string key = line.substr(0, leftBracket - 1);
            key.erase(key.find_last_not_of(" \t") + 1);
            key.erase(0, key.find_first_not_of(" \t"));
            std::string decValue = line.substr(colon + 1, rightBracket - colon - 1);
            key.erase(key.find_last_not_of(" ") + 1);
            key.erase(0, key.find_first_not_of(" "));
            std::cout << key << " = " << decValue << std::endl;
            inodeInfo[key] = std::stoull(decValue);
        }
    }
    file.close();
    return inodeInfo;
}

void GetInodeInfo(const std::string &devPath, std::unique_ptr<NodeData> &nodeData,
    int16_t &addrIndex, const uint32_t inode)
{
    if (nodeData == nullptr || devPath.empty()) {
        std::cout << "GetInodeInfo invalid parameter" << std::endl;
        return;
    }

    std::string outputFile = "/data/local/inodeInfo";
    std::vector<std::string> argv;
    argv.push_back("/system/bin/dump.f2fs");
    argv.push_back("-i");
    argv.push_back(std::to_string(inode));
    argv.push_back(devPath);

    ExecutableCmdWithOutput(argv, outputFile);

    auto inodeInfo = ParseInodeInfo(outputFile);
    GetNodeDataFromMap(nodeData, addrIndex, inodeInfo);
    system("rm -rf /data/local/inodeInfo");
}

bool PrintFsckErrorMsg(const std::string &outputFile, const std::string &devicePath)
{
    std::ifstream file(outputFile);
    if (!file.is_open()) {
        std::cout << "Failed to open file : " << outputFile << std::endl;
        return false;
    }

    std::string line;
    bool checkRes = true;
    while (std::getline(file, line)) {
        if (line.find("Fail") != std::string::npos) {
            std::cout << "fsck error : " << line << std::endl;
            checkRes = false;
        }
    }

    file.close();

    if (checkRes) {
        std::cout << "The fsck tool reported a successful check, file path : " << devicePath << std::endl;
    } else {
        std::cout << "The fsck tool reports that the check failed, file path : " << devicePath << std::endl;
    }
    return checkRes;
}

// -a 、-m 、-O "ro"  3个互斥
// 先不校验 -m 参数，需要特殊设备，配置CONFIG_BLK_DEV_ZONED
bool CheckMkfsHmfsResult(const std::map<std::string, std::string> &parameterMap,
    const std::unique_ptr<CheckPointData> &checkPoint, const std::unique_ptr<SuperBlockData> &superBlock,
    const std::unique_ptr<NodeData> &nodeData)
{
    if (checkPoint == nullptr || superBlock == nullptr) {
        return false;
    }
    std::map<std::string, std::string>::const_iterator aIter = parameterMap.find("-a");
    std::map<std::string, std::string>::const_iterator mIter = parameterMap.find("-m");
    if (superBlock->features & HMFS_FEATURE_RO) {
        if (checkPoint->curNodeSegNo[0] == 0 || checkPoint->curNodeSegNo[1] != 0 || checkPoint->curNodeSegNo[2] != 0 ||
            checkPoint->curDataSegNo[0] != 0 || checkPoint->curDataSegNo[1] != 0 || checkPoint->curDataSegNo[2] != 0) {
            std::cout << "Failed to check ro feature" << std::endl;
            return false;
        }
    } else if ((aIter != parameterMap.end()) && ((static_cast<int32_t>(std::stoi(aIter->second) != 0)))) {
        if (checkPoint->curNodeSegNo[0] == 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 ||
            checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] != 0) {
            std::cout << "Failed to check the result of parameter 'a'" << std::endl;
            return false;
        }
    } else if ((mIter != parameterMap.end()) && ((static_cast<int32_t>(std::stoi(mIter->second) != 0)))) {
        if (checkPoint->curNodeSegNo[0] != 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 ||
            checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] == 0) {
            std::cout << "Failed to check the result of parameter 'm'" << std::endl;
            return false;
        }
    } else {
        if (checkPoint->curNodeSegNo[0] != 0 || checkPoint->curNodeSegNo[1] == 0 || checkPoint->curNodeSegNo[2] == 0 ||
            checkPoint->curDataSegNo[0] == 0 || checkPoint->curDataSegNo[1] == 0 || checkPoint->curDataSegNo[2] == 0) {
            std::cout << "Failed to check the current node and data segments" << std::endl;
            return false;
        }
    }

    // -c -i 对比f2fs、hmfs执行成功后字段是否一致

    std::map<std::string, std::string>::const_iterator iter = parameterMap.find("-e");
    std::vector<std::string> extensionList;
    for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) {
        std::string extension(const_cast<char*>(superBlock->extensionList[i]));
        extensionList.push_back(extension);
    }

    if (iter != parameterMap.end() && (iter->second.size() < EXTENSION_LEN_MAX) &&
        std::find(extensionList.begin(), extensionList.end(), iter->second) == extensionList.end()) {
        std::cout << "Failed to check the result of parameter 'e',iter->second : " << iter->second << std::endl;
        return false;
    }

    iter = parameterMap.find("-E");
    if (iter != parameterMap.end() && (iter->second.size() < EXTENSION_LEN_MAX) &&
        std::find(extensionList.begin(), extensionList.end(), iter->second) == extensionList.end()) {
        std::cout << "Failed to check the result of parameter 'E',iter->second : " << iter->second << std::endl;
        return false;
    }

    iter = parameterMap.find("-l");
    if (iter != parameterMap.end()) {
        std::u16string volumeNameUtf16(reinterpret_cast<const char16_t*>(superBlock->volumeName));
        std::string volumeName = Utf16ToUtf8(volumeNameUtf16);
        if (volumeName != iter->second) {
            std::cout << "Failed to check the result of parameter 'l', volumeName : " << volumeName <<
                " iter->second : " << iter->second << std::endl;
            return false;
        }
    }

    // 检查参数-O
    iter = parameterMap.find("-O");
    if ((iter != parameterMap.end()) && (!CheckFeatures(superBlock->features, iter->second))) {
        std::cout << "Failed to check the result of parameter 'O'" << std::endl;
        return false;
    }

    // 检查参数-C
    iter = parameterMap.find("-C");
    if ((iter != parameterMap.end()) && (iter->second == "utf8") && (!(superBlock->encoding == 1)) &&
        (!(superBlock->features & HMFS_FEATURE_CASEFOLD))) {
        std::cout << "Failed to check the result of parameter 'C'" << std::endl;
        return false;
    }

    // 检查参数-R,inode根节点中的i_uid、i_gid与设置的是否一致
    iter = parameterMap.find("-R");
    if (iter != parameterMap.end()) {
        size_t colonPos = iter->second.find(':');
        if (colonPos == std::string::npos) {
            std::cout << "Failed to find colon" << std::endl;
            return false;
        }

        std::string userIdStr = iter->second.substr(0, colonPos);
        std::string groupIdStr = iter->second.substr(colonPos + 1);
        int32_t userId = static_cast<int32_t>(std::stoi(userIdStr));
        int32_t groupId = static_cast<int32_t>(std::stoi(groupIdStr));

        // 获取inode根节点中的i_uid、iGid
        if ((userId != nodeData->inode.userId) || (groupId != nodeData->inode.groupId)) {
            std::cout << "Failed to verify the userId or the groupId" << std::endl;
            return false;
        }
    }

    // 检查参数-T，inode根节点中i.iAtime、i.iCtime、i.modificationTime
    iter = parameterMap.find("-T");
    if ((iter != parameterMap.end()) && (iter->second != "-1")) {
        uint64_t timeStamp = NativeToLE32(strtoul(iter->second.c_str(), nullptr, 0));
        // 获取inode根节点中的i_atime、i.iCtime、i.modificationTime
        uint64_t accessTime = nodeData->inode.accessTime;
        uint64_t changeTime = nodeData->inode.changeTime;
        uint64_t modificationTime = nodeData->inode.modificationTime;
        if ((accessTime != timeStamp) || (changeTime != timeStamp) || (modificationTime != timeStamp)) {
            std::cout << "Failed to check the timestamp,timeStamp : " << timeStamp << " accessTime : " << accessTime <<
                " changeTime : " << changeTime << " modificationTime : " << modificationTime <<
                " nodeData.inode.accessTime = " << nodeData->inode.accessTime << " nodeData.inode.changeTime = " << nodeData->inode.changeTime <<
                " nodeData.inode.modificationTime = " << nodeData->inode.modificationTime << std::endl;
            return false;
        }
    }

    return true;
}

SuperBlockCode CompareSuperBlock(const std::unique_ptr<SuperBlockData> &f2SB, const std::unique_ptr<SuperBlockData> &hmSB)
{
    COMPARE_FIELD_RET_CODE(ERROR_LOG_SECTOR_SIZE, f2SB->logSectorSize, hmSB->logSectorSize);
    COMPARE_FIELD_RET_CODE(ERROR_LOG_SECTORS_PER_BLK, f2SB->log2SectorsPerBlock, hmSB->log2SectorsPerBlock);
    COMPARE_FIELD_RET_CODE(ERROR_LOG_BLOCK_SIZE, f2SB->logBlockSize, hmSB->logBlockSize);
    COMPARE_FIELD_RET_CODE(ERROR_LOG_BLKS_PER_SEG, f2SB->logBlksPerSeg, hmSB->logBlksPerSeg);
    COMPARE_FIELD_RET_CODE(ERROR_SEGS_PER_SECTION, f2SB->segsPerSection, hmSB->segsPerSection);

    COMPARE_FIELD_RET_CODE(ERROR_SECTIONS_PER_ZONE, f2SB->sectionsPerZone, hmSB->sectionsPerZone);
    COMPARE_FIELD_RET_CODE(ERROR_SB_CHECKSUM_OFFSET, f2SB->checksumOffset, hmSB->checksumOffset);
    COMPARE_FIELD_RET_CODE(ERROR_BLOCK_COUNT, f2SB->blockCount, hmSB->blockCount);
    COMPARE_FIELD_RET_CODE(ERROR_SECTION_COUNT, f2SB->sectionCount, hmSB->sectionCount);
    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT, f2SB->segmentCount, hmSB->segmentCount);

    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_CP, f2SB->segmentCountInCP, hmSB->segmentCountInCP);
    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_SIT, f2SB->segmentCountInSIT, hmSB->segmentCountInSIT);
    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_NAT, f2SB->segmentCountInNAT, hmSB->segmentCountInNAT);
    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_SSA, f2SB->segmentCountInSSA, hmSB->segmentCountInSSA);
    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT_COUNT_IN_MAIN, f2SB->segmentCountInMain, hmSB->segmentCountInMain);

    COMPARE_FIELD_RET_CODE(ERROR_SEGMENT0_BLKID, f2SB->segment0BlockId, hmSB->segment0BlockId);
    COMPARE_FIELD_RET_CODE(ERROR_CP_BLKID, f2SB->checkPointBlockId, hmSB->checkPointBlockId);
    COMPARE_FIELD_RET_CODE(ERROR_SIT_BLKID, f2SB->sitBlockId, hmSB->sitBlockId);
    COMPARE_FIELD_RET_CODE(ERROR_NAT_BLKID, f2SB->natBlockId, hmSB->natBlockId);
    COMPARE_FIELD_RET_CODE(ERROR_SSA_BLKID, f2SB->ssaBlockId, hmSB->ssaBlockId);

    COMPARE_FIELD_RET_CODE(ERROR_MAIN_BLKID, f2SB->mainBlockId, hmSB->mainBlockId);
    COMPARE_FIELD_RET_CODE(ERROR_ROOT_INODE_ID, f2SB->rootInodeId, hmSB->rootInodeId);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_INODE_ID, f2SB->nodeInodeId, hmSB->nodeInodeId);
    COMPARE_FIELD_RET_CODE(ERROR_META_INODE_ID, f2SB->metaInodeId, hmSB->metaInodeId);
    COMPARE_FIELD_RET_CODE(ERROR_EXTENSION_COUNT, f2SB->coldExtensionCount, hmSB->coldExtensionCount);

    COMPARE_FIELD_RET_CODE(ERROR_VOLUME_NAME, f2SB->volumeName, f2SB->volumeName + VOLUME_NAME_MAX_LEN, hmSB->volumeName);

    std::vector<std::string> f2fsExtList;
    std::vector<std::string> hmfsExtList;
    for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) {
        std::string extension(const_cast<char*>(f2SB->extensionList[i]));
        f2fsExtList.push_back(extension);
    }
    for (int32_t i = 0; i < EXTENSION_COUNT_MAX; ++i) {
        std::string extension(const_cast<char*>(hmSB->extensionList[i]));
        hmfsExtList.push_back(extension);
    }

    COMPARE_FIELD_RET_CODE(ERROR_EXTENSION_LIST, f2fsExtList.begin(), f2fsExtList.end(), hmfsExtList.begin(), hmfsExtList.end());
    COMPARE_FIELD_RET_CODE(ERROR_CP_PAY_LOAD, f2SB->checkPointPayload, hmSB->checkPointPayload);
    COMPARE_FIELD_RET_CODE(ERROR_FEATURES, f2SB->features, hmSB->features);
    COMPARE_FIELD_RET_CODE(ERROR_ENCRYPTION_LEVEL, f2SB->encryptionLevel, hmSB->encryptionLevel);

    COMPARE_FIELD_RET_CODE(ERROR_HOT_EXTENSION_COUNT, f2SB->hotExtensionCount, hmSB->hotExtensionCount);
    COMPARE_FIELD_RET_CODE(ERROR_S_ENCODING, f2SB->encoding, hmSB->encoding);
    COMPARE_FIELD_RET_CODE(ERROR_S_ENCODING_FLAGS, f2SB->encodingFlags, hmSB->encodingFlags);
    return SUCCESSED_SB;
}

CheckPointCode CompareCheckPoint(const std::unique_ptr<CheckPointData> &f2CP, const std::unique_ptr<CheckPointData> &hmCP)
{
    COMPARE_FIELD_RET_CODE(ERROR_USER_BLOCK_COUNT, f2CP->userBlockCount, hmCP->userBlockCount);
    COMPARE_FIELD_RET_CODE(ERROR_VALID_BLOCK_COUNT, f2CP->validBlockCount, hmCP->validBlockCount);
    COMPARE_FIELD_RET_CODE(ERROR_RSVD_SEGMENT_COUNT, f2CP->reservedSegmentCount, hmCP->reservedSegmentCount);
    COMPARE_FIELD_RET_CODE(ERROR_OVERPROV_SEGMENT_COUNT, f2CP->overprovisionSegmentCount, hmCP->overprovisionSegmentCount);
    COMPARE_FIELD_RET_CODE(ERROR_FREE_SEGMENT_COUNT, f2CP->freeSegmentCount, hmCP->freeSegmentCount);

    COMPARE_FIELD_RET_CODE(ERROR_CUR_NODE_SEG_NO, f2CP->curNodeSegNo, f2CP->curNodeSegNo +
        CURSEG_NODE_TYPE_COUNT, hmCP->curNodeSegNo);
    COMPARE_FIELD_RET_CODE(ERROR_CUR_NODE_BLK_OFFSET, f2CP->curNodeBlkOffset,
        f2CP->curNodeBlkOffset + CURSEG_NODE_TYPE_COUNT, hmCP->curNodeBlkOffset);
    COMPARE_FIELD_RET_CODE(ERROR_CUR_DATA_SEG_NO, f2CP->curDataSegNo, f2CP->curDataSegNo +
        CURSEG_DATA_TYPE_COUNT, hmCP->curDataSegNo);
    COMPARE_FIELD_RET_CODE(ERROR_CUR_DATA_BLK_OFFSET, f2CP->curDataBlkOffset,
        f2CP->curDataBlkOffset + CURSEG_DATA_TYPE_COUNT, hmCP->curDataBlkOffset);
    COMPARE_FIELD_RET_CODE(ERROR_ALLOC_TYPE, f2CP->allocType, f2CP->allocType + static_cast<unsigned char>(CURSEG_NODE_COLD),
        hmCP->allocType);
#ifndef HMFS_UNIT_TEST_RESIZE
    COMPARE_FIELD_RET_CODE(ERROR_CP_FLAGS, f2CP->checkPointFlags, hmCP->checkPointFlags);
#endif
    COMPARE_FIELD_RET_CODE(ERROR_CP_PACK_BLOCK_COUNT, f2CP->checkPointPackBlockCount, hmCP->checkPointPackBlockCount);
    COMPARE_FIELD_RET_CODE(ERROR_CP_PACK_START_SUM, f2CP->checkPointPackBlockCount, hmCP->checkPointPackBlockCount);
    COMPARE_FIELD_RET_CODE(ERROR_VALID_NODE_COUNT, f2CP->validNodeCount, hmCP->validNodeCount);
    COMPARE_FIELD_RET_CODE(ERROR_VALID_INODE_COUNT, f2CP->validInodeCount, hmCP->validInodeCount);

    COMPARE_FIELD_RET_CODE(ERROR_NEXT_FREE_NODE_ID, f2CP->nextFreeNodeId, hmCP->nextFreeNodeId);
    COMPARE_FIELD_RET_CODE(ERROR_SIT_VERSION_BITMAP_SIZE, f2CP->sitVersionBitmapSize, hmCP->sitVersionBitmapSize);
    COMPARE_FIELD_RET_CODE(ERROR_NAT_VERSION_BITMAP_SIZE, f2CP->natVersionBitmapSize, hmCP->natVersionBitmapSize);
    COMPARE_FIELD_RET_CODE(ERROR_CP_CHECKSUM_OFFSET, f2CP->checksumOffset, hmCP->checksumOffset);

    return SUCCESSED_CP;
}

NodeDataCode CompareNodeData(const std::unique_ptr<NodeData> &f2CP, const std::unique_ptr<NodeData> &hmCP,
    const int16_t addrIndex, const bool compTime)
{
    COMPARE_FIELD_RET_CODE(ERROR_NODE_MODE, f2CP->inode.fileMode, hmCP->inode.fileMode);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_ADVISE, f2CP->inode.fileHints, hmCP->inode.fileHints);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_UID, f2CP->inode.userId, hmCP->inode.userId);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_GID, f2CP->inode.groupId, hmCP->inode.groupId);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_LINKS, f2CP->inode.linkCount, hmCP->inode.linkCount);

    COMPARE_FIELD_RET_CODE(ERROR_NODE_SIZE, f2CP->inode.fileSize, hmCP->inode.fileSize);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_BLOCKS, f2CP->inode.blockSize, hmCP->inode.blockSize);

    if (compTime) {
        COMPARE_FIELD_RET_CODE(ERROR_NODE_ATIME, f2CP->inode.accessTime, hmCP->inode.accessTime);
        COMPARE_FIELD_RET_CODE(ERROR_NODE_ATIME_NSEC, f2CP->inode.accessTimeNsec, hmCP->inode.accessTimeNsec);
        COMPARE_FIELD_RET_CODE(ERROR_NODE_CTIME, f2CP->inode.changeTime, hmCP->inode.changeTime);
        COMPARE_FIELD_RET_CODE(ERROR_NODE_CTIME_NSEC, f2CP->inode.changeTimeNsec, hmCP->inode.changeTimeNsec);
        COMPARE_FIELD_RET_CODE(ERROR_NODE_MTIME, f2CP->inode.modificationTime, hmCP->inode.modificationTime);
        COMPARE_FIELD_RET_CODE(ERROR_NODE_MTIME_NSEC, f2CP->inode.modificationTimeNsec, hmCP->inode.modificationTimeNsec);
    }

    COMPARE_FIELD_RET_CODE(ERROR_NODE_GENRATION, f2CP->inode.fileVersion, hmCP->inode.fileVersion);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_CURRENT_DEPTH, f2CP->inode.directoryDepth, hmCP->inode.directoryDepth);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_XATTR_NID, f2CP->inode.xattrNodeId, hmCP->inode.xattrNodeId);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_FLAGS, f2CP->inode.fileAttributes, hmCP->inode.fileAttributes);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_INLINE, f2CP->inode.inlineFlags, hmCP->inode.inlineFlags);

    COMPARE_FIELD_RET_CODE(ERROR_NODE_PINO, f2CP->inode.parentInodeNumber, hmCP->inode.parentInodeNumber);
    COMPARE_FIELD_RET_CODE(ERROR_NODE_DIR_LEVEL, f2CP->inode.directoryLevel, hmCP->inode.directoryLevel);

    COMPARE_FIELD_RET_CODE(ERROR_NODE_ADDR, f2CP->inode.dataBlocksAddr[addrIndex], hmCP->inode.dataBlocksAddr[addrIndex]);

    COMPARE_FIELD_RET_CODE(ERROR_NODE_NID, f2CP->inode.nodeIds, f2CP->inode.nodeIds + 4,
        hmCP->inode.nodeIds, hmCP->inode.nodeIds + 4);

    return SUCCESSED_ND;
}

void PrintRawSuperBlockInfo(const std::unique_ptr<SuperBlockData> &superBlock)
{
    if (superBlock == nullptr) {
        return;
    }
    std::cout << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;
    std::cout << "| hmfs Super block                                       |" << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;

    PRINT_TO_COLSOLE(superBlock, magicNumber);
    PRINT_TO_COLSOLE(superBlock, majorVersion);

    PRINT_TO_COLSOLE(superBlock, minorVersion);
    PRINT_TO_COLSOLE(superBlock, logSectorSize);
    PRINT_TO_COLSOLE(superBlock, log2SectorsPerBlock);

    PRINT_TO_COLSOLE(superBlock, logBlockSize);
    PRINT_TO_COLSOLE(superBlock, logBlksPerSeg);
    PRINT_TO_COLSOLE(superBlock, segsPerSection);
    PRINT_TO_COLSOLE(superBlock, sectionsPerZone);
    PRINT_TO_COLSOLE(superBlock, checksumOffset);
    PRINT_TO_COLSOLE(superBlock, blockCount);

    PRINT_TO_COLSOLE(superBlock, sectionCount);
    PRINT_TO_COLSOLE(superBlock, segmentCount);
    PRINT_TO_COLSOLE(superBlock, segmentCountInCP);
    PRINT_TO_COLSOLE(superBlock, segmentCountInSIT);
    PRINT_TO_COLSOLE(superBlock, segmentCountInNAT);

    PRINT_TO_COLSOLE(superBlock, segmentCountInSSA);
    PRINT_TO_COLSOLE(superBlock, segmentCountInMain);
    PRINT_TO_COLSOLE(superBlock, segment0BlockId);

    PRINT_TO_COLSOLE(superBlock, checkPointBlockId);
    PRINT_TO_COLSOLE(superBlock, sitBlockId);
    PRINT_TO_COLSOLE(superBlock, natBlockId);
    PRINT_TO_COLSOLE(superBlock, ssaBlockId);
    PRINT_TO_COLSOLE(superBlock, mainBlockId);

    PRINT_TO_COLSOLE(superBlock, rootInodeId);
    PRINT_TO_COLSOLE(superBlock, nodeInodeId);
    PRINT_TO_COLSOLE(superBlock, metaInodeId);
    PRINT_TO_COLSOLE(superBlock, checkPointPayload);
    PRINT_TO_COLSOLE(superBlock, checksum);
    printf("%-25s%-.255s", "version", superBlock->version);
    std::cout << std::endl;
}

void PrintCPInfo(const std::unique_ptr<CheckPointData> &checkPoint)
{
    std::cout << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;
    std::cout << "| hmfs Checkpoint                                        |" << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;

    PRINT_TO_COLSOLE(checkPoint, checkPointVersion);
    PRINT_TO_COLSOLE(checkPoint, userBlockCount);
    PRINT_TO_COLSOLE(checkPoint, validBlockCount);
    PRINT_TO_COLSOLE(checkPoint, reservedSegmentCount);
    PRINT_TO_COLSOLE(checkPoint, overprovisionSegmentCount);
    PRINT_TO_COLSOLE(checkPoint, freeSegmentCount);

    PRINT_TO_COLSOLE(checkPoint, allocType[3]);
    PRINT_TO_COLSOLE(checkPoint, allocType[4]);
    PRINT_TO_COLSOLE(checkPoint, allocType[5]);
    PRINT_TO_COLSOLE(checkPoint, curNodeSegNo[0]);
    PRINT_TO_COLSOLE(checkPoint, curNodeSegNo[1]);
    PRINT_TO_COLSOLE(checkPoint, curNodeSegNo[2]);

    PRINT_TO_COLSOLE(checkPoint, curNodeBlkOffset[0]);
    PRINT_TO_COLSOLE(checkPoint, curNodeBlkOffset[1]);
    PRINT_TO_COLSOLE(checkPoint, curNodeBlkOffset[2]);


    PRINT_TO_COLSOLE(checkPoint, allocType[0]);
    PRINT_TO_COLSOLE(checkPoint, allocType[1]);
    PRINT_TO_COLSOLE(checkPoint, allocType[2]);
    PRINT_TO_COLSOLE(checkPoint, curDataSegNo[0]);
    PRINT_TO_COLSOLE(checkPoint, curDataSegNo[1]);
    PRINT_TO_COLSOLE(checkPoint, curDataSegNo[2]);

    PRINT_TO_COLSOLE(checkPoint, curDataBlkOffset[0]);
    PRINT_TO_COLSOLE(checkPoint, curDataBlkOffset[1]);
    PRINT_TO_COLSOLE(checkPoint, curDataBlkOffset[2]);

    PRINT_TO_COLSOLE(checkPoint, checkPointFlags);
    PRINT_TO_COLSOLE(checkPoint, checkPointPackBlockCount);
    PRINT_TO_COLSOLE(checkPoint, summaryStartBlock);
    PRINT_TO_COLSOLE(checkPoint, validNodeCount);
    PRINT_TO_COLSOLE(checkPoint, validInodeCount);
    PRINT_TO_COLSOLE(checkPoint, nextFreeNodeId);
    PRINT_TO_COLSOLE(checkPoint, sitVersionBitmapSize);
    PRINT_TO_COLSOLE(checkPoint, natVersionBitmapSize);
    PRINT_TO_COLSOLE(checkPoint, checksumOffset);
    PRINT_TO_COLSOLE(checkPoint, mountElapsedTime);

    PRINT_TO_COLSOLE(checkPoint, sitNatVersionBitmap[0]);
    std::cout << std::endl;
}

void PrintInodeInfo(uint32_t features, const std::unique_ptr<NodeData> &node,
    const int16_t addrIndex, const uint32_t iNodeNum)
{
    std::cout << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;
    std::cout << "| hmfs IndeInfo iNodeNum : " << iNodeNum << "                        |" << std::endl;
    std::cout << "+--------------------------------------------------------+" << std::endl;

    auto inode = &node->inode;
    PRINT_TO_COLSOLE(inode, fileMode);
    PRINT_TO_COLSOLE(inode, fileHints);
    PRINT_TO_COLSOLE(inode, userId);
    PRINT_TO_COLSOLE(inode, groupId);
    PRINT_TO_COLSOLE(inode, linkCount);
    PRINT_TO_COLSOLE(inode, fileSize);
    PRINT_TO_COLSOLE(inode, blockSize);

    PRINT_TO_COLSOLE(inode, accessTime);
    PRINT_TO_COLSOLE(inode, accessTimeNsec);
    PRINT_TO_COLSOLE(inode, changeTime);
    PRINT_TO_COLSOLE(inode, changeTimeNsec);
    PRINT_TO_COLSOLE(inode, modificationTime);
    PRINT_TO_COLSOLE(inode, modificationTimeNsec);

    PRINT_TO_COLSOLE(inode, fileVersion);
    PRINT_TO_COLSOLE(inode, directoryDepth);
    PRINT_TO_COLSOLE(inode, xattrNodeId);
    PRINT_TO_COLSOLE(inode, fileAttributes);
    PRINT_TO_COLSOLE(inode, inlineFlags);
    PRINT_TO_COLSOLE(inode, parentInodeNumber);
    PRINT_TO_COLSOLE(inode, directoryLevel);

    if (features & HMFS_FEATURE_EXTRA_ATTR) {
        PRINT_TO_COLSOLE(inode, extraInodeSize);
        if (features & HMFS_FEATURE_FLEXIBLE_INLINE_XATTR) {
            PRINT_TO_COLSOLE(inode, inlineXattrSize);
        }
        if (features & HMFS_FEATURE_PRJQUOTA) {
            PRINT_TO_COLSOLE(inode, projectId);
        }
        if (features & HMFS_FEATURE_INODE_CRTIME) {
            PRINT_TO_COLSOLE(inode, creationTime);
            PRINT_TO_COLSOLE(inode, creationTimeNsec);
        }
        if (features & HMFS_FEATURE_COMPRESSION) {
            PRINT_TO_COLSOLE(inode, compressedBlockCount);
            PRINT_TO_COLSOLE(inode, compressionAlgorithm);
            PRINT_TO_COLSOLE(inode, logClusterSize);
            PRINT_TO_COLSOLE(inode, padding);
        }
    }

    std::cout << "i.dataBlocksAddr[0x" << std::hex << addrIndex << "] = " <<
        std::dec << node->inode.dataBlocksAddr[addrIndex] << std::endl;

    PRINT_TO_COLSOLE(inode, nodeIds[0]);    /* direct */
    PRINT_TO_COLSOLE(inode, nodeIds[1]);    /* direct */
    PRINT_TO_COLSOLE(inode, nodeIds[2]);    /* indirect */
    PRINT_TO_COLSOLE(inode, nodeIds[3]);    /* indirect */
    PRINT_TO_COLSOLE(inode, nodeIds[4]);    /* double indirect */

    std::cout << std::endl;
}

void PrintSuperBlockAndCheckPointData(const std::string &device)
{
    auto hmfsSuperBlock = std::make_unique<SuperBlockData>();
    GetSuperBlock(device, hmfsSuperBlock);
    PrintRawSuperBlockInfo(hmfsSuperBlock);

    auto checkPoint = std::make_unique<CheckPointData>();
    GetCheckPoint(device, checkPoint);
    PrintCPInfo(checkPoint);
}
} // namespace Hmfs
} // namespace OHOS